
from sqlalchemy.orm import *
from sqlalchemy.types import * 
from sqlalchemy import create_engine
from typing import Optional
from sqlalchemy import select
import numpy as np
from .user import user,select_all as select_all_user
class Base(DeclarativeBase):
    def _asdict(self):
        return {column.name: getattr(self, column.name) for column in self.__table__.columns}

class user_tag(Base):
    __tablename__="user_tag"
    id : Mapped[Integer] = mapped_column( Integer, nullable=False,primary_key=True, autoincrement=True, ) 
    user_id : Mapped[Integer] = mapped_column( Integer,  ) 
    username : Mapped[String] = mapped_column( String,  ) 
    tags : Mapped[JSON] = mapped_column( JSON,  )





def select_all(engine):
    with Session(engine) as session :
        return [rec._asdict() for rec in session.query(user_tag).all()]
    
def select_by_col(engine,cond:dict):
    with Session(engine) as session :
        return [rec._asdict() for rec in session.query(user_tag).filter_by(**cond).all()]


def update_one(engine,cond:dict,item:dict):
    with Session(engine) as session:
        record = session.query(user_tag).filter_by(**cond).first()
        if record:
            # Update the record with the new values
            for key, value in item.items():
                setattr(record, key, value)
            session.commit()
            return True
        return False 
    
def add_one(engine,item:dict):
    try:
        with Session(engine) as session :
            record = user_tag(**item)
            session.add(record)
            session.commit()
            return True 
    except Exception as e:
        print(e)
        return False
    
def delete_one(engine,cond:dict):
    try:
        with Session(engine) as session :
            record = session.query(user_tag).filter_by(id=cond['id']).first()
            session.delete(record)
            session.commit()
            return True 
    except Exception as e:
        return False  
def delete_batch(engine,cond:dict):
    try:
        with Session(engine) as session :
            records = session.query(user_tag).filter_by(**cond).all()
            for rec in records:
                session.delete(rec)
            session.commit()
            return True 
    except Exception as e:
        return False  


def find_top_k_index(arr:np.ndarray,k:int):
    return arr.argsort()[-k:][::-1]

def recommend(engine,target_user:int):
    N = 5
    with Session(engine) as session :
        user_tags = session.query(user_tag).all()
        user_tags = [rec._asdict() for rec in user_tags]
        print(user_tags)
        # Get the target user's tags
        target_user_tags = [rec for rec in user_tags if rec["user_id"]==target_user]
        target_user_tags = target_user_tags[0]["tags"]

        num_user = len(user_tags)
        vecs = []
        user_tags = [rec for rec in user_tags if rec["user_id"]!=target_user]
        for user in user_tags:
            v = np.zeros(N)
            for tag in user["tags"]:
                v[int(tag)] = 1
            vecs.append(v)
        vecs = np.array(vecs)
        target_user_vec = np.zeros(N)
        for tag in target_user_tags:
            target_user_vec[int(tag)] = 1

        # cos sim
        sims = []
        for vec in vecs:
            sim = np.dot(target_user_vec,vec)/(np.linalg.norm(target_user_vec)*np.linalg.norm(vec))
            sims.append(sim)
        sims = np.array(sims)
        print(sims)
        top_k_index = find_top_k_index(sims,2)
        rec_user = []
        for index in top_k_index:
            rec_user.append(user_tags[index]["user_id"])
        users = select_all_user(engine)

        rec_user = [rec for rec in users if rec["id"] in rec_user]
        return rec_user